package io.xxx.xbutler.service;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.hy.corecode.idgen.WFGIdGenerator;
import io.xxx.xbutler.common.RedisKeys;
import io.xxx.xbutler.data.*;
import io.xxx.xbutler.domain.*;
import io.xxx.xbutler.sdk.TanJingClient;
import io.xxx.xbutler.sdk.domain.AppMsg;
import io.xxx.xbutler.sdk.domain.Msg;
import io.xxx.xbutler.sdk.domain.PrivateChatMessage;
import io.xxx.xbutler.sdk.domain.WeAppInfo;
import io.xxx.xbutler.sdk.request.ScanCodeSignRequest;
import io.xxx.xbutler.sdk.request.SendPrivateChatMessagesRequest;
import io.xxx.xbutler.sdk.response.ScanCodeSignResponse;
import io.xxx.xbutler.sdk.response.SendChatMessagesResponse;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.LocalDateTime;
import java.util.Collections;

@Slf4j
@Service
public class RobotService {

    private final XmlMapper xmlMapper = new XmlMapper();

    @Resource
    private WFGIdGenerator idGenerator;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TanJingClient tanJingClient;

    @Resource
    private RobotMapper robotMapper;

    @Resource
    private RobotLoginMapper robotLoginMapper;

    @Resource
    private StoreMapper storeMapper;

    @Resource
    private RobotStoreMapper robotStoreMapper;

    @Resource
    private RobotApplyMapper robotApplyMapper;

    @Value("${mini-program.path.bind-store:/bind_store}")
    private String path;

    public Page<Robot> list(Integer pageNumber, Integer pageSize) {
        LambdaQueryWrapper<Robot> wrapper = new LambdaQueryWrapper<>();
        return robotMapper.selectPage(new Page<>(pageNumber, pageSize), wrapper);
    }

    /**
     * 门店申领机器人
     * <p>
     * 申领机器人后有可能不会立即分配到机器人，通过定时任务进行分配
     *
     * @return 申领单号
     */
    public String apply(RobotApply apply) {
        RLock lock = redissonClient.getLock(RedisKeys.applyRobotLock(apply.getStoreId()));
        if (lock.tryLock()) {
            Long id = idGenerator.next();
            apply.setId(id)
                    .setBind(false)
                    .setSendBind(false)
                    .setCreatedTime(LocalDateTime.now());
            robotApplyMapper.insert(apply);
            return id.toString();
        } else {
            throw new RuntimeException("门店正在申请机器人！");
        }
    }

    /**
     * 初次登录和重新登录其回调是一样的
     */
    public String login(String robotId, String robotSerialNo) {
        ScanCodeSignRequest request = new ScanCodeSignRequest();
        request.setProtocolType(1);
        request.setIsCacheLogin(false);
        request.setRobotSerialNo("");
        request.setRegionCode(430100);
        request.setIsOfficialAccountAuth(false);
        request.setMachineNo(null);
        request.setRelationSerialNo(null);
        request.setIsVipDevice(false);

        if (StringUtils.hasText(robotSerialNo)) {
            request.setRobotSerialNo(robotSerialNo);
        } else if (StringUtils.hasText(robotId)) {
            Robot robot = robotMapper.selectById(robotId);
            if (robot != null) {
                request.setRobotSerialNo(robot.getSerialNo());
            }
        }
        ScanCodeSignResponse response = tanJingClient.execute(request);
        return response.getSerialNo();
    }

    /**
     * 调用扫码登录接口之后通过响应中的serialNo查询是否收到了1001回调
     */
    public RobotLogin getLoginQrcode(String serialNo) {
        LambdaQueryWrapper<RobotLogin> wrapper = new LambdaQueryWrapper<RobotLogin>()
                .eq(RobotLogin::getSerialNo, serialNo);
        return robotLoginMapper.selectOne(wrapper);
    }

    public void bindStore(String robotId, Store store) {
        LocalDateTime now = LocalDateTime.now();
        Long storeId = store.getId();
        boolean storeExists = isExists(storeId);
        if (!storeExists) {
            store.setCreatedTime(now)
                    .setUpdatedTime(now);
            storeMapper.insert(store);
        }

        boolean robotStoreExists = isExists(robotId, storeId);
        if (!robotStoreExists) {
            RobotStore robotStore = new RobotStore()
                    .setId(idGenerator.next())
                    .setRobotId(robotId)
                    .setStoreId(storeId)
                    .setStoreCode(store.getCode())
                    .setStoreName(store.getName())
                    .setCreatedTime(now);
            robotStoreMapper.insert(robotStore);
        }
    }

    private boolean isExists(Long storeId) {
        LambdaQueryWrapper<Store> wrapper = new LambdaQueryWrapper<Store>()
                .eq(Store::getId, storeId);
        return storeMapper.exists(wrapper);
    }

    private boolean isExists(String robotId, Long storeId) {
        LambdaQueryWrapper<RobotStore> wrapper = new LambdaQueryWrapper<RobotStore>()
                .eq(RobotStore::getRobotId, robotId)
                .eq(RobotStore::getStoreId, storeId);
        return robotStoreMapper.exists(wrapper);
    }

    public void sendBind(Long robotApplyId) {
        RobotApply apply = robotApplyMapper.selectById(robotApplyId);
        sendBind(apply.getRobotId(), apply.getRobotSerialNo(), apply.getContactSerialNo());
    }

    @SneakyThrows
    public void sendBind(String robotId, String robotSerialNo, String contactSerialNo) {
        Msg msg = new Msg();
        AppMsg appMsg = new AppMsg();
        msg.setAppMsg(appMsg);

        WeAppInfo weAppInfo = new WeAppInfo();
        appMsg.setWeAppInfo(weAppInfo);

        appMsg.setTitle("兴盛优选")
                .setDescription("兴盛优选")
                .setType("type")
                .setUrl("url")
                .setSourceUsername("sourceUsername")
                .setSourceDisplayName("sourceDisplayName");

        String pagePath = UriComponentsBuilder.fromPath(path)
                .queryParam("robotSerialNo", robotSerialNo)
                .queryParam("robotId", robotId)
                .toUriString();
        weAppInfo.setUsername("username")
                .setAppid("appid")
                .setType("type")
                .setVersion("version")
                .setWeAppIconUrl("weAppIconUrl")
                .setPagePath(pagePath);

        PrivateChatMessage message = new PrivateChatMessage()
                .setMsgNum(1L)
                .setMsgType(2013)
                .setMsgContent(xmlMapper.writeValueAsString(msg));

        SendPrivateChatMessagesRequest request = (SendPrivateChatMessagesRequest) new SendPrivateChatMessagesRequest()
                .setToWxSerialNo(contactSerialNo)
                .setRobotSerialNo(robotSerialNo)
                .setRelaSerialNo("bindStore:" + idGenerator.next())    // 回调通过解析realSerialNo来处理消息发送成功之后的后续操作
                .setData(Collections.singletonList(message));

        SendChatMessagesResponse response = tanJingClient.execute(request);
        LambdaUpdateWrapper<RobotApply> wrapper = new LambdaUpdateWrapper<RobotApply>()
                .set(RobotApply::getUpdatedTime, LocalDateTime.now());
        if (response.isSuccess()) {
            wrapper.set(RobotApply::getSendBind, true);
        } else {
            log.error("绑定卡片发送失败[robotId:{}, robotSerialNo:{}, contactSerialNo:{}, request:{}, response:{}]",
                    robotId, robotSerialNo, contactSerialNo, JSON.toJSONString(request.params()), JSON.toJSONString(response));
            wrapper.set(RobotApply::getSendBind, false);
        }
        robotApplyMapper.update(wrapper);
    }

    public RobotApply getApply(Long storeId) {
        return robotApplyMapper.findByStoreId(storeId);
    }
}
